﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace SkypeBot.Commands
{
    using SkypeBot.Core;

    class CommandExecutor
    {
        private readonly List<ICommandMapper> _mappers = new List<ICommandMapper>();
        public void RegisterMessageHandler(IMessageHandler handler)
        {
            Type handlerType = handler.GetType();

            foreach (MethodInfo endpoint in handlerType.GetMethods(BindingFlags.Public | BindingFlags.Instance))
            {
                var messageAttributes = endpoint.GetCustomAttributes(typeof(MessageAttribute), false);
                foreach (MessageAttribute messageAttribute in messageAttributes)
                {
                    var mapper = new DefaultCommandMapper(handler, endpoint, messageAttribute._pattern);
                    _mappers.Add(mapper);
                }
            }
        }

        public Responce ExecuteCommand(Message message)
        {
            Responce objReponce = null;

            try
            {

                foreach (var mapper in _mappers.Where(r => r.IsMatch(message)))
                {
                    var inputParameters = new Dictionary<string, string>();

                    inputParameters = mapper.GetInputParameters(message);

                    var parameters = BuildParameters(mapper.EndPoint, message, inputParameters);
                    objReponce = (Responce)mapper.EndPoint.Invoke(mapper.Handler, parameters);
                }


            }
            catch (Exception e)
            {
            }

            return objReponce; 
        }

        private object[] BuildParameters(MethodInfo method, Message message,  Dictionary<string, string> inputParameters)
        {
            ParameterInfo[] methodParameters = method.GetParameters();
            var result = new object[methodParameters.Count()];

            for (int parameterIndex = 0; parameterIndex < result.Length; parameterIndex++)
            {
                ParameterInfo parameter = methodParameters[parameterIndex];

                if (parameter.ParameterType.IsAssignableFrom(typeof(Message)))
                {
                    result[parameterIndex] = message;
                }
                else if (inputParameters.ContainsKey(parameter.Name))
                {
                    result[parameterIndex] = Convert.ChangeType(inputParameters[parameter.Name], parameter.ParameterType);
                }
            }

            return result;
        }
    }
}
